/**
 * 格式化日期
 * @param options 配置选项
 * @param options.date 日期对象、时间戳或日期字符串
 * @param options.format 格式字符串，默认为 'YYYY-MM-DD HH:mm:ss'
 * @returns 格式化后的日期字符串
 */
export function formatDate(options: {
  date: Date | number | string
  format?: string
}): string {
  const { date, format = 'YYYY-MM-DD HH:mm:ss' } = options
  const d = new Date(date)
  
  if (Number.isNaN(d.getTime())) {
    return ''
  }

  const year = d.getFullYear()
  const month = d.getMonth() + 1
  const day = d.getDate()
  const hour = d.getHours()
  const minute = d.getMinutes()
  const second = d.getSeconds()
  const millisecond = d.getMilliseconds()

  const formatMap: Record<string, string> = {
    'YYYY': String(year),
    'YY': String(year).slice(-2),
    'MM': String(month).padStart(2, '0'),
    'M': String(month),
    'DD': String(day).padStart(2, '0'),
    'D': String(day),
    'HH': String(hour).padStart(2, '0'),
    'H': String(hour),
    'mm': String(minute).padStart(2, '0'),
    'm': String(minute),
    'ss': String(second).padStart(2, '0'),
    's': String(second),
    'SSS': String(millisecond).padStart(3, '0'),
  }

  return format.replace(/YYYY|YY|MM|M|DD|D|HH|H|mm|m|ss|s|SSS/g, (match) => {
    return formatMap[match] || match
  })
}

/**
 * 格式化相对时间
 * @param options 配置选项
 * @param options.date 日期对象、时间戳或日期字符串
 * @param options.baseDate 基准日期，默认为当前时间
 * @returns 相对时间字符串
 */
export function formatRelativeTime(options: {
  date: Date | number | string
  baseDate?: Date | number | string
}): string {
  const { date, baseDate } = options
  const targetDate = new Date(date)
  const base = baseDate ? new Date(baseDate) : new Date()
  
  if (Number.isNaN(targetDate.getTime()) || Number.isNaN(base.getTime())) {
    return ''
  }

  const diff = base.getTime() - targetDate.getTime()
  const absDiff = Math.abs(diff)
  const isFuture = diff < 0

  const minute = 60 * 1000
  const hour = 60 * minute
  const day = 24 * hour
  const week = 7 * day
  const month = 30 * day
  const year = 365 * day

  if (absDiff < minute) {
    return '刚刚'
  }
  else if (absDiff < hour) {
    const minutes = Math.floor(absDiff / minute)
    return isFuture ? `${minutes}分钟后` : `${minutes}分钟前`
  }
  else if (absDiff < day) {
    const hours = Math.floor(absDiff / hour)
    return isFuture ? `${hours}小时后` : `${hours}小时前`
  }
  else if (absDiff < week) {
    const days = Math.floor(absDiff / day)
    return isFuture ? `${days}天后` : `${days}天前`
  }
  else if (absDiff < month) {
    const weeks = Math.floor(absDiff / week)
    return isFuture ? `${weeks}周后` : `${weeks}周前`
  }
  else if (absDiff < year) {
    const months = Math.floor(absDiff / month)
    return isFuture ? `${months}个月后` : `${months}个月前`
  }
  else {
    const years = Math.floor(absDiff / year)
    return isFuture ? `${years}年后` : `${years}年前`
  }
}

/**
 * 获取时间戳
 * @param options 配置选项
 * @param options.date 日期对象、时间戳或日期字符串，默认为当前时间
 * @param options.unit 时间戳单位，'ms' 为毫秒，'s' 为秒，默认为 'ms'
 * @returns 时间戳
 */
export function getTimestamp(options: {
  date?: Date | number | string
  unit?: 'ms' | 's'
} = {}): number {
  const { date = new Date(), unit = 'ms' } = options
  const timestamp = new Date(date).getTime()
  return unit === 's' ? Math.floor(timestamp / 1000) : timestamp
}

/**
 * 获取今天的开始时间
 * @param options 配置选项
 * @param options.date 指定日期，默认为当前日期
 * @returns 今天开始时间的 Date 对象
 */
export function getStartOfDay(options: {
  date?: Date | number | string
} = {}): Date {
  const { date = new Date() } = options
  const d = new Date(date)
  d.setHours(0, 0, 0, 0)
  return d
}

/**
 * 获取今天的结束时间
 * @param options 配置选项
 * @param options.date 指定日期，默认为当前日期
 * @returns 今天结束时间的 Date 对象
 */
export function getEndOfDay(options: {
  date?: Date | number | string
} = {}): Date {
  const { date = new Date() } = options
  const d = new Date(date)
  d.setHours(23, 59, 59, 999)
  return d
}

/**
 * 获取本周的开始时间（周一）
 * @param options 配置选项
 * @param options.date 指定日期，默认为当前日期
 * @returns 本周开始时间的 Date 对象
 */
export function getStartOfWeek(options: {
  date?: Date | number | string
} = {}): Date {
  const { date = new Date() } = options
  const d = new Date(date)
  const day = d.getDay()
  const diff = d.getDate() - day + (day === 0 ? -6 : 1) // 调整为周一开始
  d.setDate(diff)
  d.setHours(0, 0, 0, 0)
  return d
}

/**
 * 获取本周的结束时间（周日）
 * @param options 配置选项
 * @param options.date 指定日期，默认为当前日期
 * @returns 本周结束时间的 Date 对象
 */
export function getEndOfWeek(options: {
  date?: Date | number | string
} = {}): Date {
  const { date = new Date() } = options
  const d = new Date(date)
  const day = d.getDay()
  const diff = d.getDate() - day + (day === 0 ? 0 : 7) // 调整为周日结束
  d.setDate(diff)
  d.setHours(23, 59, 59, 999)
  return d
}

/**
 * 获取本月的开始时间
 * @param options 配置选项
 * @param options.date 指定日期，默认为当前日期
 * @returns 本月开始时间的 Date 对象
 */
export function getStartOfMonth(options: {
  date?: Date | number | string
} = {}): Date {
  const { date = new Date() } = options
  const d = new Date(date)
  d.setDate(1)
  d.setHours(0, 0, 0, 0)
  return d
}

/**
 * 获取本月的结束时间
 * @param options 配置选项
 * @param options.date 指定日期，默认为当前日期
 * @returns 本月结束时间的 Date 对象
 */
export function getEndOfMonth(options: {
  date?: Date | number | string
} = {}): Date {
  const { date = new Date() } = options
  const d = new Date(date)
  d.setMonth(d.getMonth() + 1, 0)
  d.setHours(23, 59, 59, 999)
  return d
}

/**
 * 获取本年的开始时间
 * @param options 配置选项
 * @param options.date 指定日期，默认为当前日期
 * @returns 本年开始时间的 Date 对象
 */
export function getStartOfYear(options: {
  date?: Date | number | string
} = {}): Date {
  const { date = new Date() } = options
  const d = new Date(date)
  d.setMonth(0, 1)
  d.setHours(0, 0, 0, 0)
  return d
}

/**
 * 获取本年的结束时间
 * @param options 配置选项
 * @param options.date 指定日期，默认为当前日期
 * @returns 本年结束时间的 Date 对象
 */
export function getEndOfYear(options: {
  date?: Date | number | string
} = {}): Date {
  const { date = new Date() } = options
  const d = new Date(date)
  d.setMonth(11, 31)
  d.setHours(23, 59, 59, 999)
  return d
}

/**
 * 添加时间
 * @param options 配置选项
 * @param options.date 基准日期
 * @param options.amount 添加的数量
 * @param options.unit 时间单位
 * @returns 添加后的 Date 对象
 */
export function addTime(options: {
  date: Date | number | string
  amount: number
  unit: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond'
}): Date {
  const { date, amount, unit } = options
  const d = new Date(date)
  
  switch (unit) {
    case 'year':
      d.setFullYear(d.getFullYear() + amount)
      break
    case 'month':
      d.setMonth(d.getMonth() + amount)
      break
    case 'day':
      d.setDate(d.getDate() + amount)
      break
    case 'hour':
      d.setHours(d.getHours() + amount)
      break
    case 'minute':
      d.setMinutes(d.getMinutes() + amount)
      break
    case 'second':
      d.setSeconds(d.getSeconds() + amount)
      break
    case 'millisecond':
      d.setMilliseconds(d.getMilliseconds() + amount)
      break
  }
  
  return d
}

/**
 * 减少时间
 * @param options 配置选项
 * @param options.date 基准日期
 * @param options.amount 减少的数量
 * @param options.unit 时间单位
 * @returns 减少后的 Date 对象
 */
export function subtractTime(options: {
  date: Date | number | string
  amount: number
  unit: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond'
}): Date {
  const { date, amount, unit } = options
  return addTime({ date, amount: -amount, unit })
}

/**
 * 计算两个日期之间的差值
 * @param options 配置选项
 * @param options.date1 第一个日期
 * @param options.date2 第二个日期
 * @param options.unit 返回的时间单位
 * @returns 时间差值
 */
export function diffTime(options: {
  date1: Date | number | string
  date2: Date | number | string
  unit?: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond'
}): number {
  const { date1, date2, unit = 'millisecond' } = options
  const d1 = new Date(date1)
  const d2 = new Date(date2)
  const diff = d1.getTime() - d2.getTime()
  
  switch (unit) {
    case 'year':
      return Math.floor(diff / (365 * 24 * 60 * 60 * 1000))
    case 'month':
      return Math.floor(diff / (30 * 24 * 60 * 60 * 1000))
    case 'day':
      return Math.floor(diff / (24 * 60 * 60 * 1000))
    case 'hour':
      return Math.floor(diff / (60 * 60 * 1000))
    case 'minute':
      return Math.floor(diff / (60 * 1000))
    case 'second':
      return Math.floor(diff / 1000)
    case 'millisecond':
    default:
      return diff
  }
}

/**
 * 判断是否为同一天
 * @param options 配置选项
 * @param options.date1 第一个日期
 * @param options.date2 第二个日期
 * @returns 是否为同一天
 */
export function isSameDay(options: {
  date1: Date | number | string
  date2: Date | number | string
}): boolean {
  const { date1, date2 } = options
  const d1 = new Date(date1)
  const d2 = new Date(date2)
  
  return d1.getFullYear() === d2.getFullYear() &&
         d1.getMonth() === d2.getMonth() &&
         d1.getDate() === d2.getDate()
}

/**
 * 判断是否为同一周
 * @param options 配置选项
 * @param options.date1 第一个日期
 * @param options.date2 第二个日期
 * @returns 是否为同一周
 */
export function isSameWeek(options: {
  date1: Date | number | string
  date2: Date | number | string
}): boolean {
  const { date1, date2 } = options
  const start1 = getStartOfWeek({ date: date1 })
  const start2 = getStartOfWeek({ date: date2 })
  
  return isSameDay({ date1: start1, date2: start2 })
}

/**
 * 判断是否为同一月
 * @param options 配置选项
 * @param options.date1 第一个日期
 * @param options.date2 第二个日期
 * @returns 是否为同一月
 */
export function isSameMonth(options: {
  date1: Date | number | string
  date2: Date | number | string
}): boolean {
  const { date1, date2 } = options
  const d1 = new Date(date1)
  const d2 = new Date(date2)
  
  return d1.getFullYear() === d2.getFullYear() &&
         d1.getMonth() === d2.getMonth()
}

/**
 * 判断是否为同一年
 * @param options 配置选项
 * @param options.date1 第一个日期
 * @param options.date2 第二个日期
 * @returns 是否为同一年
 */
export function isSameYear(options: {
  date1: Date | number | string
  date2: Date | number | string
}): boolean {
  const { date1, date2 } = options
  const d1 = new Date(date1)
  const d2 = new Date(date2)
  
  return d1.getFullYear() === d2.getFullYear()
}

/**
 * 判断是否为今天
 * @param options 配置选项
 * @param options.date 要判断的日期
 * @returns 是否为今天
 */
export function isToday(options: {
  date: Date | number | string
}): boolean {
  const { date } = options
  return isSameDay({ date1: date, date2: new Date() })
}

/**
 * 判断是否为昨天
 * @param options 配置选项
 * @param options.date 要判断的日期
 * @returns 是否为昨天
 */
export function isYesterday(options: {
  date: Date | number | string
}): boolean {
  const { date } = options
  const yesterday = subtractTime({ date: new Date(), amount: 1, unit: 'day' })
  return isSameDay({ date1: date, date2: yesterday })
}

/**
 * 判断是否为明天
 * @param options 配置选项
 * @param options.date 要判断的日期
 * @returns 是否为明天
 */
export function isTomorrow(options: {
  date: Date | number | string
}): boolean {
  const { date } = options
  const tomorrow = addTime({ date: new Date(), amount: 1, unit: 'day' })
  return isSameDay({ date1: date, date2: tomorrow })
}

/**
 * 判断是否为本周
 * @param options 配置选项
 * @param options.date 要判断的日期
 * @returns 是否为本周
 */
export function isThisWeek(options: {
  date: Date | number | string
}): boolean {
  const { date } = options
  return isSameWeek({ date1: date, date2: new Date() })
}

/**
 * 判断是否为本月
 * @param options 配置选项
 * @param options.date 要判断的日期
 * @returns 是否为本月
 */
export function isThisMonth(options: {
  date: Date | number | string
}): boolean {
  const { date } = options
  return isSameMonth({ date1: date, date2: new Date() })
}

/**
 * 判断是否为本年
 * @param options 配置选项
 * @param options.date 要判断的日期
 * @returns 是否为本年
 */
export function isThisYear(options: {
  date: Date | number | string
}): boolean {
  const { date } = options
  return isSameYear({ date1: date, date2: new Date() })
}

/**
 * 判断是否为闰年
 * @param options 配置选项
 * @param options.year 年份
 * @returns 是否为闰年
 */
export function isLeapYear(options: {
  year: number
}): boolean {
  const { year } = options
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0)
}

/**
 * 获取某月的天数
 * @param options 配置选项
 * @param options.year 年份
 * @param options.month 月份（1-12）
 * @returns 该月的天数
 */
export function getDaysInMonth(options: {
  year: number
  month: number
}): number {
  const { year, month } = options
  return new Date(year, month, 0).getDate()
}

/**
 * 获取某年的天数
 * @param options 配置选项
 * @param options.year 年份
 * @returns 该年的天数
 */
export function getDaysInYear(options: {
  year: number
}): number {
  const { year } = options
  return isLeapYear({ year }) ? 366 : 365
}

/**
 * 获取星期几
 * @param options 配置选项
 * @param options.date 日期
 * @param options.format 格式，'number' 返回数字（0-6），'chinese' 返回中文
 * @returns 星期几
 */
export function getWeekday(options: {
  date: Date | number | string
  format?: 'number' | 'chinese'
}): number | string {
  const { date, format = 'number' } = options
  const d = new Date(date)
  const day = d.getDay()
  
  if (format === 'chinese') {
    const weekdays = ['日', '一', '二', '三', '四', '五', '六']
    return `星期${weekdays[day]}`
  }
  
  return day
}

/**
 * 睡眠函数
 * @param options 配置选项
 * @param options.ms 睡眠时间（毫秒）
 * @returns Promise
 */
export function sleep(options: {
  ms: number
}): Promise<void> {
  const { ms } = options
  return new Promise(resolve => setTimeout(resolve, ms))
}

/**
 * 重试函数
 * @param options 配置选项
 * @param options.fn 要重试的函数
 * @param options.maxRetries 最大重试次数，默认为 3
 * @param options.delay 重试间隔（毫秒），默认为 1000
 * @returns Promise
 */
export async function retry<T>(options: {
  fn: () => Promise<T>
  maxRetries?: number
  delay?: number
}): Promise<T> {
  const { fn, maxRetries = 3, delay = 1000 } = options
  let lastError: Error
  
  for (let i = 0; i <= maxRetries; i++) {
    try {
      return await fn()
    }
    catch (error) {
      lastError = error as Error
      if (i < maxRetries) {
        await sleep({ ms: delay })
      }
    }
  }
  
  throw lastError || new Error('重试失败')
}

/**
 * 防抖函数
 * @param options 配置选项
 * @param options.fn 要防抖的函数
 * @param options.delay 延迟时间（毫秒）
 * @returns 防抖后的函数
 */
export function debounce<T extends (...args: any[]) => any>(options: {
  fn: T
  delay: number
}): (...args: Parameters<T>) => void {
  const { fn, delay } = options
  let timeoutId: ReturnType<typeof setTimeout>
  
  return (...args: Parameters<T>) => {
    clearTimeout(timeoutId)
    timeoutId = setTimeout(() => fn(...args), delay)
  }
}

/**
 * 节流函数
 * @param options 配置选项
 * @param options.fn 要节流的函数
 * @param options.delay 延迟时间（毫秒）
 * @returns 节流后的函数
 */
export function throttle<T extends (...args: any[]) => any>(options: {
  fn: T
  delay: number
}): (...args: Parameters<T>) => void {
  const { fn, delay } = options
  let lastCall = 0
  
  return (...args: Parameters<T>) => {
    const now = Date.now()
    if (now - lastCall >= delay) {
      lastCall = now
      fn(...args)
    }
  }
}

/**
 * 格式化持续时间
 * @param options 配置选项
 * @param options.ms 持续时间（毫秒）
 * @param options.format 格式，'full' 为完整格式，'short' 为简短格式
 * @returns 格式化后的持续时间字符串
 */
export function formatDuration(options: {
  ms: number
  format?: 'full' | 'short'
}): string {
  const { ms, format = 'full' } = options
  const seconds = Math.floor(ms / 1000)
  const minutes = Math.floor(seconds / 60)
  const hours = Math.floor(minutes / 60)
  const days = Math.floor(hours / 24)
  
  const remainingHours = hours % 24
  const remainingMinutes = minutes % 60
  const remainingSeconds = seconds % 60
  
  if (format === 'short') {
    if (days > 0) return `${days}d ${remainingHours}h`
    if (hours > 0) return `${hours}h ${remainingMinutes}m`
    if (minutes > 0) return `${minutes}m ${remainingSeconds}s`
    return `${seconds}s`
  }
  
  const parts: string[] = []
  if (days > 0) parts.push(`${days}天`)
  if (remainingHours > 0) parts.push(`${remainingHours}小时`)
  if (remainingMinutes > 0) parts.push(`${remainingMinutes}分钟`)
  if (remainingSeconds > 0) parts.push(`${remainingSeconds}秒`)
  
  return parts.join('') || '0秒'
}